package com.yanggeng.demo.beginnerguidedemo.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewGroup;

import com.yanggeng.demo.beginnerguidedemo.R;
import com.yanggeng.demo.beginnerguidedemo.bean.Topology;
import com.yanggeng.demo.beginnerguidedemo.utils.DeviceParams;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TopologyView extends View implements ScaleGestureDetector.OnScaleGestureListener {

    private int mDeviceWidth, mPortHeight, mPortWidth, mPortDividerHeight, mTextSize;

    private int mDeviceColor, mPortColor, mLineColor, mDeviceTextColor, mPortTextColor;

    private Paint mRectanglePaint, mLinePaint, mTextPaint;

    private Topology mTopology;


    private int mCurrTier = 0;
    private int mCurrHeight = 0;
    private int mHeight, mWidth;
    private float mScale = 1f;
    private float mPortInsidePercent = 0.4f; // 端口矩形 mPortInsidePercent的比例在设备矩形中
    private int mArrowHeight = 15;
    private int mArrowWidth = 5;
    private ScaleGestureDetector mScaleGestureDetector;
    private Map<Integer, Integer> mHeightMap = new HashMap<>(); // 绘制过程中每一基当前的高度
    private Map<Integer, Integer> mMaxHeightMap = new HashMap<>(); // 每一基的所有设备的高度和
    private int mTranslateHeight = 0;
    private Map<Integer, Integer> mLineX = new HashMap<>(); // 画连接线时，每一基当前的偏移量

    public TopologyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TopologyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mDeviceWidth = DeviceParams.dip2px(context, 80);
        mPortHeight = DeviceParams.dip2px(context, 22);
        mPortDividerHeight = DeviceParams.dip2px(context, 10);
        mTextSize = DeviceParams.sp2px(context, 13);
        mPortWidth = DeviceParams.dip2px(context, 50);
        mDeviceColor = context.getResources().getColor(R.color.device_color);
        mPortColor = context.getResources().getColor(R.color.port_color);
        mLineColor = context.getResources().getColor(R.color.line_color);
        mDeviceTextColor = context.getResources().getColor(R.color.text_black);
        mPortTextColor = context.getResources().getColor(R.color.white);
        mRectanglePaint = new Paint();
        mRectanglePaint.setStyle(Paint.Style.FILL);

        mLinePaint = new Paint();
        mLinePaint.setStrokeWidth(2);
        mLinePaint.setColor(mLineColor);

        mTextPaint = new Paint();
        mTextPaint.setTextSize(mTextSize);
        mTextPaint.setTextAlign(Paint.Align.CENTER);

        mScaleGestureDetector = new ScaleGestureDetector(context, this);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int max = 0;
        for (Integer key : mMaxHeightMap.keySet()) {
            if (mMaxHeightMap.get(key) > max) {
                max = mMaxHeightMap.get(key);
            }
        }
        mHeight = max;
        mWidth = mDeviceWidth * 2 * mMaxHeightMap.keySet().size();
        setMeasuredDimension(mWidth, max);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mHeightMap.clear();
        mCurrTier = 0;
        mCurrHeight = 0;
        canvas.translate(50, 50);
        drawDevice(canvas, mTopology);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

    private void drawDevice(Canvas canvas, Topology topology) {
        // 1、画一个设备，带有topology.getSize()个端口
        List<Topology.PortBean> portBeans = topology.getPorts();
        int height;
        if (topology.getSize() > 0) {
            height = mPortHeight * topology.getSize() + mPortDividerHeight * (topology.getSize() + 2);
        } else {
            height = mPortHeight * 3;
        }

        if (topology.getTier() == 0) {
            mTranslateHeight = (mHeight - mMaxHeightMap.get(topology.getTier())) / 2;
            canvas.translate(0, mTranslateHeight);
        }

        if (topology.getTier() != mCurrTier) {

            int translateHeight = (mHeight - mMaxHeightMap.get(topology.getTier())) / 2 - mTranslateHeight;
            int translateWidth = mDeviceWidth * 2 * (topology.getTier() - mCurrTier);
            // 移动画布
            canvas.translate(translateWidth, translateHeight);
            mCurrTier = topology.getTier();
            mTranslateHeight = (mHeight - mMaxHeightMap.get(topology.getTier())) / 2;
            if (mHeightMap.get(topology.getTier()) != null) {
                mCurrHeight = mHeightMap.get(topology.getTier());
            } else {
                mCurrHeight = 0;
            }
        }
        mRectanglePaint.setColor(mDeviceColor);
        // 画设备矩形
        canvas.drawRect(0, mCurrHeight, mDeviceWidth, height + mCurrHeight, mRectanglePaint);
        mTextPaint.setColor(mDeviceTextColor);
        canvas.drawText(topology.getType(), mDeviceWidth / 2, height + mCurrHeight - height / 2 + getTextBounds(topology.getType(), mTextPaint).height() / 2, mTextPaint);

        Log.e("Topology", "drawRect currHeight: " + mCurrHeight + " tier: " + mCurrTier);

        mRectanglePaint.setColor(mPortColor);
        mTextPaint.setColor(mPortTextColor);
        if (topology.getTier() > 0) {
            // 画接收端口矩形
            canvas.drawRect(-mPortWidth * (1 - mPortInsidePercent), mCurrHeight + mPortDividerHeight, mPortWidth * mPortInsidePercent, mCurrHeight + mPortDividerHeight + mPortHeight, mRectanglePaint);
            canvas.drawText("SFP A", mPortWidth * mPortInsidePercent - mPortWidth / 2, mCurrHeight + mPortDividerHeight + mPortHeight - (mPortHeight - getTextBounds("SFP A", mTextPaint).height()) / 2, mTextPaint);
        }

        // 画端口矩形
        for (int i = 0; i < topology.getSize(); i++) {
            canvas.drawRect(mDeviceWidth - mPortWidth * mPortInsidePercent, mPortDividerHeight * (i + 1) + mPortHeight * i + mCurrHeight, mDeviceWidth + mPortWidth * (1 - mPortInsidePercent), (mPortDividerHeight + mPortHeight) * (i + 1) + mCurrHeight, mRectanglePaint);
            canvas.drawText("SFP " + (i + 1), mDeviceWidth + mPortWidth * (1 - mPortInsidePercent) - mPortWidth / 2, (mPortDividerHeight + mPortHeight) * (i + 1) + mCurrHeight - (mPortHeight - getTextBounds("SFP 1", mTextPaint).height()) / 2, mTextPaint);
        }

        // 画箭头连接线
        if (portBeans != null) {
            Map<Integer, Integer> heightMap = new HashMap<>();
            for (int i = 0; i < portBeans.size(); i++) {
                float startX = mDeviceWidth + mPortWidth * (1 - mPortInsidePercent);
                float startY = mPortDividerHeight * (i + 1) + mPortHeight * i + mPortHeight / 2 + mCurrHeight;
                float endX;


                float endY;
                int nextHeight;
                if (heightMap.get(mCurrTier + 1) != null) {
                    endY = heightMap.get(mCurrTier + 1) + mPortDividerHeight + mPortHeight - ((mMaxHeightMap.get(mCurrTier + 1) - mMaxHeightMap.get(mCurrTier)) / 2);
                    if (portBeans.get(i).getDevice().getSize() > 0) {
                        nextHeight = mPortHeight * portBeans.get(i).getDevice().getSize() + mPortDividerHeight * (portBeans.get(i).getDevice().getSize() + 2);
                    } else {
                        nextHeight = mPortHeight * 3;
                    }
                    heightMap.put(mCurrTier + 1, nextHeight + mPortHeight * 2 + heightMap.get(mCurrTier + 1));
                } else {
                    if (mHeightMap.get(mCurrTier + 1) != null) {
                        endY = (mMaxHeightMap.get(mCurrTier) - mMaxHeightMap.get(mCurrTier + 1)) / 2 + mPortDividerHeight + mPortHeight + mHeightMap.get(mCurrTier + 1);
                    } else {
                        endY = (mMaxHeightMap.get(mCurrTier) - mMaxHeightMap.get(mCurrTier + 1)) / 2 + mPortDividerHeight + mPortHeight;
                    }
                    if (portBeans.get(i).getDevice().getSize() > 0) {
                        nextHeight = mPortHeight * portBeans.get(i).getDevice().getSize() + mPortDividerHeight * (portBeans.get(i).getDevice().getSize() + 2);
                    } else {
                        nextHeight = mPortHeight * 3;
                    }
                    if (mHeightMap.get(mCurrTier + 1) != null) {
                        heightMap.put(mCurrTier + 1, nextHeight + mPortHeight * 2 + mHeightMap.get(mCurrTier + 1));
                    } else {
                        heightMap.put(mCurrTier + 1, nextHeight + mPortHeight * 2);
                    }
                }
                if (endY - startY > 0) {
                    // 终点在起点下方
                    if (mLineX.get(mCurrTier) != null && mLineX.get(mCurrTier) < 0) {
                        endX = mDeviceWidth * 2f + mLineX.get(mCurrTier);
                        mLineX.put(mCurrTier, mLineX.get(mCurrTier) - 10);
                    } else {
                        endX = mDeviceWidth * 2f - 20;
                        mLineX.put(mCurrTier, -30);
                    }
                    if (endX - (mDeviceWidth * 2 - mPortWidth * (1 - mPortInsidePercent)) < 15) {
                        mLineX.put(mCurrTier, -20);
                    }
                } else {
                    // 终点在起点上方
                    if (mLineX.get(mCurrTier) != null && mLineX.get(mCurrTier) > 0) {
                        endX = mDeviceWidth * 2f - mPortWidth * (1 - mPortInsidePercent) + mLineX.get(mCurrTier);
                        mLineX.put(mCurrTier, mLineX.get(mCurrTier) + 10);
                    } else {
                        endX = mDeviceWidth * 2f - mPortWidth * (1 - mPortInsidePercent) + 20;
                        mLineX.put(mCurrTier, 30);
                    }
                    if (mDeviceWidth * 2 - endX < 20) {
                        mLineX.put(mCurrTier, 20);
                    }
                }

                Path path = new Path();
                path.moveTo(endX, endY);
                if (endY - startY <= mPortHeight && endY - startY >= 0) {
                    endY = startY;
                    endX = mDeviceWidth * 2f - mPortWidth * (1 - mPortInsidePercent);
                    path.lineTo(endX - mArrowHeight, endY - mArrowWidth);
                    path.lineTo(endX - mArrowHeight, endY + mArrowWidth);
                    path.lineTo(endX, endY);
                } else if (endY - startY > mPortHeight) {
                    endY -= mPortHeight;
                    path.lineTo(endX - mArrowWidth, endY - mArrowHeight);
                    path.lineTo(endX + mArrowWidth, endY - mArrowHeight);
                    path.lineTo(endX, endY);
                } else {
                    path.lineTo(endX - mArrowWidth, endY + mArrowHeight);
                    path.lineTo(endX + mArrowWidth, endY + mArrowHeight);
                    path.lineTo(endX, endY);
                }

                path.close();
                mLinePaint.setColor(Color.RED);
                canvas.drawPath(path, mLinePaint);
//                Path path = new Path();
//                path.moveTo(startX, startY);
//                path.lineTo(endX, startY);
//                path.lineTo(endX, endY);
//                canvas.drawPath(path, mLinePaint);
                canvas.drawLine(startX, startY, endX, startY, mLinePaint);
                canvas.drawLine(endX, startY, endX, endY, mLinePaint);
            }
        }

        // 2、根据每个端口中连接的设备device 画下一级设备
        mCurrHeight += height + mPortHeight * 2;
        mHeightMap.put(topology.getTier(), mCurrHeight);
        if (portBeans != null && portBeans.size() > 0) {

            for (Topology.PortBean portBean : portBeans) {
                drawDevice(canvas, portBean.getDevice());
            }
        }
    }

    public void setData(Topology topology) {
        if (topology != null) {
            mTopology = topology;
            mMaxHeightMap.clear();
            mHeightMap.clear();
            mLineX.clear();
            mCurrHeight = 0;
            mTranslateHeight = 0;
            mCurrTier = 0;
            initHeight(mTopology);
            mCurrHeight = 0;
            mCurrTier = 0;
            requestLayout();
            invalidate();
        }
    }

    private void initHeight(Topology topology) {
        int height;
        if (topology.getSize() > 0) {
            height = mPortHeight * topology.getSize() + mPortDividerHeight * (topology.getSize() + 2);
        } else {
            height = mPortHeight * 3;
        }
        if (topology.getTier() != mCurrTier) {
            mCurrTier = topology.getTier();
            if (mMaxHeightMap.get(topology.getTier()) != null) {
                mCurrHeight = mMaxHeightMap.get(topology.getTier());
            } else {
                mCurrHeight = 0;
            }
        }
        mCurrHeight += height + mPortHeight * 2;
        mMaxHeightMap.put(topology.getTier(), mCurrHeight);
        List<Topology.PortBean> portBeans = topology.getPorts();
        if (portBeans != null && portBeans.size() > 0) {
            for (Topology.PortBean portBean : portBeans) {
                initHeight(portBean.getDevice());
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        mScaleGestureDetector.onTouchEvent(ev);
        return true;
    }

    /**
     * 获取丈量文本的矩形
     *
     * @param text
     * @param paint
     * @return
     */
    private Rect getTextBounds(String text, Paint paint) {
        Rect rect = new Rect();
        paint.getTextBounds(text, 0, text.length(), rect);
        return rect;
    }


    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        float currScale = detector.getScaleFactor();
        Log.e("TopologyView", "curr scale: " + mScale);
        if (mScale * currScale < 0.7 || mScale * currScale > 1.5) {
            currScale = 1f;
        } else {
            mScale *= currScale;
        }
        Log.e("TopologyView", "currScale: " + currScale + " scale: " + detector.getScaleFactor());

        setScaleX(mScale);
        setScaleY(mScale);
        onUpdateScale(mScale);

//        mDeviceWidth *= currScale;
//        mPortHeight *= currScale;
//        mPortWidth *= currScale;
//        mPortDividerHeight *= currScale;
//        mTextSize *= currScale;
//        mTextPaint.setTextSize(mTextSize);
//        mHeightMap.clear();
//        mLineX.clear();
//        mTranslateHeight = 0;
//        for (Map.Entry<Integer, Integer> entry : mMaxHeightMap.entrySet()) {
//            entry.setValue((int) (entry.getValue() * currScale));
//        }
//        mCurrHeight = 0;
//        mCurrTier = 0;
        // TODO: 2018/8/14 缩放会出现错乱
        return true;
    }

    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {

    }

    private void onUpdateScale(float scale) {
        ViewGroup.LayoutParams params = getLayoutParams();
        params.width = (int) (mWidth * scale);
        params.height = (int) (mHeight * scale);
        setLayoutParams(params);
    }
}
